package com.bookmanager.www.controller;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bookmanager.www.common.DTO.CreateOrderByBookIdDTO;
import com.bookmanager.www.common.DTO.SearchOrdersDTO;
import com.bookmanager.www.common.async.AsyncTask;
import com.bookmanager.www.common.utils.CommonsUtils;
import com.bookmanager.www.common.utils.OffersAndRatingsUtils;
import com.bookmanager.www.common.utils.Result;
import com.bookmanager.www.entity.*;
import com.bookmanager.www.mapper.*;
import com.bookmanager.www.service.FlBookorderService;
import com.bookmanager.www.service.FlCartsService;
import com.bookmanager.www.service.FlPayinfoService;
import com.bookmanager.www.service.SearchService;
import com.github.xiaoymin.swaggerbootstrapui.util.CommonUtils;
import com.sun.jna.IntegerType;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * <p>
 * 图书订单 前端控制器
 * </p>
 *
 * @author 风离
 * @since 2021-09-17
 */
@RestController
@RequestMapping("/fl-bookOrder")
@Api(tags = "订单管理")
@Slf4j
public class FlBookOrderController {
    @Resource
    FlCartsMapper flCartsMapper;
    @Resource
    FlBookorderService flBookorderService;
    @Resource
    FlBookorderMapper flBookorderMapper;
    @Resource
    FlAddressMapper flAddressMapper;
    @Resource
    FlCartsService flCartsService;

    @Resource
    FlBookMapper flBookMapper;

    @Resource
    FlUserMapper flUserMapper;

    @Resource
    FlPayinfoService flPayinfoService;

    @Resource
    RabbitTemplate rabbitTemplate;

    @Resource
    AsyncTask asyncTask;

    /**
     * //临时解决方案 把订单项存入Es中 随时取 (淘汰。)
     */
    @Resource
    SearchService searchService;

    @Value("${mayikt.order.exchange}")
    private String orderExchange; //订单交换机

    @Value("${mayikt.order.routingKey}")
    private String orderRoutingKey; //订单路由key




    /**
     * 取消/删除订单
     */
    @PostMapping("/cancelOrDeleteOrder")
    @ApiOperation(value = "取消/删除订单",notes = "status = -1 取消订单 status = -2 删除订单")
    Result cancelOrDeleteOrder(@RequestParam("orderId")String orderId,@RequestParam("status")Integer status)
    {
        int updateOrder = flBookorderMapper.changeStatusByOrderId(orderId,status);
        if(updateOrder!=0)
        {
            return Result.succ("取消/删除订单成功","");
        }
        return Result.fail("取消/删除订单失败","");
    }



    /**
     * 确认收货
     */
    @PostMapping("/acknowledgeReceipt")
    @ApiOperation(value = "确认收货",notes = "确认收货由用户来完成~")
    Result acknowledgeReceipt(@RequestParam("orderId")String orderId)
    {
        FlBookOrder flBookOrder=flBookorderMapper.selectOrderByOrderId(orderId);
        if(flBookOrder!=null)
        {
            int status=flBookOrder.getStatus();
            //如果是没发货状态就不允许确认收货
            if(status==0)
            {
                return Result.fail("订单未支付！！","");
            }else if(status==1)
            {
                return Result.fail("订单已支付但未发货请耐心等待！！","");
            }
            else if(status==3)
            {
                return Result.fail("订单已完成交易无需重复确认收货！！","");
            }else {
                int updateStatus = flBookorderMapper.changeStatusByOrderId(orderId,3);
                if(updateStatus!=0)
                {
                    return Result.succ("订单确认收货成功！！订单完成","");
                }
                return Result.fail("数据库未更新状态！！","");
            }
        }

        return Result.fail("找不到该订单信息~","");
    }


    /**
     * 余额支付订单逻辑 首先查询用户身份 不同身份对应不同折扣
     */
    @PostMapping("/payForOrderByBalance")
    @ApiOperation(value = "余额方式支付订单",notes = "传入用户id 订单id 即可")
    @Transactional //开启事务
    Result payloadForOrderByBalance(@RequestParam("payPassword")String payPassword,@RequestParam("userId")String userId ,@RequestParam("orderId")String orderId)
    {
        String encryptPassword = CommonsUtils.encryptPassword(payPassword, "fl1906");
        if(!encryptPassword.equals(flUserMapper.selectUserPayPasswordByUserId(userId)))
        {
            return Result.fail("支付密码错误，请重新输入！！","");
        }

        //根据用户id查询用户身份
        int accountLevel = flUserMapper.selectAccountLevelByUserId(userId);
        double discount = OffersAndRatingsUtils.getTheDiscount(accountLevel);

        FlBookOrder flBookOrder =flBookorderMapper.selectOrderByOrderId(orderId);
        BigDecimal price = flBookOrder.getPayment();
        BigDecimal newPrice = price.multiply(new BigDecimal(discount));
        System.out.println("折扣后的价格为："+newPrice);

        BigDecimal accountBalance = flUserMapper.selectAccountBalanceByUserId(userId);
        if(accountBalance.compareTo(newPrice)==-1)
        {
            return Result.fail("余额不足请充值！","");
        }

        int update = flUserMapper.changeAccountBalanceByUserId(userId, accountBalance.subtract(newPrice));
        if(update!=0)
        {
            //修改订单状态为已支付 并创建支付小票
//            int update2 = flBookorderMapper.changeStatusByOrderId(orderId, 1);

            //既然已经支付 支付时间和消费金额 创建支付小票应该是异步的 这里出现问题不能影响用户体验
//            int update3 = flBookorderMapper.updatePaymentTime(orderId, LocalDateTime.now());
//            int update4 = flUserMapper.addCumulativeConsumption(userId,Double.parseDouble(price.toString()));
//            System.out.println("支付时间是否更新？"+update3);
//            System.out.println("累计消费金额是否更新？"+update4);
            //==============================================================================================================
            //new 改为异步编程
            asyncTask.addCumulativeConsumption(userId,Double.parseDouble(price.toString()));
            asyncTask.updatePaymentTime(orderId,LocalDateTime.now());
            asyncTask.createPayInfo(userId,orderId);

            //修改订单支付类型为余额支付
            asyncTask.updatePaymentType(orderId,3);

//            if(update2!=0)
//            {
//                String payId = IdUtil.getSnowflake().nextIdStr();
//                String platformNumber = IdUtil.simpleUUID();
//                String payplatform = "3";
//                FlPayinfo payInfo = flPayinfoService.createPayInfo(userId, payId, orderId, payplatform, platformNumber);
//                if(payInfo!=null)
//                {
//                    System.out.println("支付小票"+payInfo);
//                    return Result.succ("支付成功！！",payInfo);
//                }
//
//            }
            return Result.succ("支付成功！！","");

        }

        return Result.fail("支付失败！","");
    }



    /**
     *  创建订单逻辑（直接购买）
     *  首先判断该地址id是否存在
     *  传入用户id 图书id和购买数量 和地址id即可
     * @return
     * @throws IOException
     */
    @PostMapping("/createOrderByBookId")
    @ApiOperation(value = "通过直接购买创建用户订单",notes = "传入用户id 图书id 购买数量 地址id即可")
    @Transactional(rollbackFor = Exception.class)
    Result createOrderByBookId(@RequestBody @Validated CreateOrderByBookIdDTO cDTO)
    {
        FlAddress flAddress =flAddressMapper.selectAddressByUserIdAndAddressId(cDTO.getUserId(),cDTO.getAddressId());
        if(flAddress==null)
        {
            return Result.fail("该用户无该地址id！！！","");
        }

        double price = Double.valueOf(flBookMapper.selectBookByISBN(cDTO.getBookId()).getPrice())*cDTO.getCount();
        // PaymentType = -1 表示创建订单时未指定付款方式
        FlBookOrder flBookOrder = flBookorderService.createOrderPlus(cDTO.getUserId(),price,cDTO.getAddressId(),-1);
        if(flBookOrder!=null)
        {
            String orderId =flBookOrder.getOrderId();
            FlBookTemp flBookTemp=flBookorderService.createOrderTemp(orderId,cDTO.getBookId(),cDTO.getCount());
            if(flBookTemp!=null)
            {
                String test = addOrder(orderId);
                log.warn("是否添加订单到RabbitMQ中?"+test);
                return Result.succ("创建订单成功！",orderId);
            }
        }
        return Result.fail("创建订单失败！","");
    }



    public String addOrder(String orderId){
        log.warn("进入添加订单方法中了" +
                "");
//        String orderId="110812521016363";
        //rabbit投递消息
        rabbitTemplate.convertAndSend(orderExchange,orderRoutingKey,orderId,messagePostProcessor());
        return "success";
    }

    //处理待发送消息
    private MessagePostProcessor messagePostProcessor(){
        return  new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //设置有效期30分钟
                message.getMessageProperties().setExpiration("1800000");
//                message.getMessageProperties().setExpiration("20000");
                return message;
            }
        };
    }



    @PostMapping("/createOrderByCart")
    @ApiOperation(value = "通过购物车创建用户订单",notes = "传入用户id 和地址id即可 ")
    /**
     * 创建订单逻辑 （购物车：）
     * 首先用户传入用户id 和创建类型 我来获取用户购物车信息 把勾选状态的商品id 数量取出来 留着备用
     * 转入订单列表之后 购物车里已提交的商品将会被清空
     * 关于订单列表的用户地址 返回给  前端所有地址信息  默认 默认地址创建购物车订单
     * 用户如果想要更换地址信息即在未提交订单前发起请求来更改地址信息
     *
     */
    @Transactional
    Result getCreateOrderByCart(@RequestParam("userId")String userId,@RequestParam("addressId")String addressId) throws IOException {
           List<FlCarts> flCartsList = flCartsMapper.selectCartsByUserIdAndCheckType(userId,1);
           flCartsList.forEach(System.out::println);
           System.out.println("购物车数量：："+flCartsList.size());
           if(flCartsList.size()==0)
           {
               return Result.fail("生成订单失败","购物车无商品！！！");
           }
           List<Object> bookList = new ArrayList<>();

           // 图书Id集合
           String[] bookIds=new String[flCartsList.size()];
           List bookList2 = new LinkedList();

           //获取购物车总价值
           double cartPrice  = flCartsService.getAllCartsPrice(userId);
           //创建用户订单信息
           FlBookOrder flBookOrder =flBookorderService.createOrderPlus(userId,cartPrice,addressId,-1);
           System.out.println("创建订单订单信息为"+flBookOrder);
           for (int i=0;i<flCartsList.size();i++)
           {

               Map bookMap = new LinkedHashMap();
               FlCarts flCarts = flCartsList.get(i);
               FlBookTemp createdBookTemp = flBookorderService.createOrderTemp(flBookOrder.getOrderId(),flCarts.getBookId(),flCarts.getCount());

               bookMap.put("bookId",createdBookTemp.getBookId());
               bookMap.put("bookDetail",flBookMapper.selectBookByISBN(createdBookTemp.getBookId()));
               bookMap.put("count",createdBookTemp.getCount());
//            bookMap.put("bookTemp",createdBookTemp);
               bookMap.put("orderId",flBookOrder.getOrderId());
               bookMap.put("addressId",flBookOrder.getAddressId());
               bookList2.add(bookMap);
               bookIds[i]=flCarts.getBookId();
               bookList.add(bookMap);
           }

           //根据用户选择的地址id 获取地址信息
           FlAddress flAddress=flAddressMapper.selectAddressByAddressId(addressId);
           System.out.println("用户地址信息为："+flAddress);

//        int update =0;
//        if(flBookOrder!=null)
//       {
//           //给地址加上订单标识
//           String orderId= flBookOrder.getOrderId();
////           String addressId =flAddress.getAddressId();
//           update =flAddressMapper.addOrderIdByAddressId(addressId,orderId);
//       }
           bookList.add(MapUtil.builder().put("order",flBookOrder).put("address",flAddress).build());

           //图书对应库存减少
           for (int i=0;i<flCartsList.size();i++)
           {
               FlCarts flCarts = flCartsList.get(i);
               int updated = flBookMapper.reduceBooksStock(flCarts.getBookId(),flCarts.getCount());
           }

           //创建订单成功之后清空购物车信息 （这里可以设置删除字段 1 已删除 2未删除 好像不太行。
           // ）
           int deleteBatch = flCartsMapper.deleteBatch(userId, bookIds);
           if(deleteBatch==flCartsList.size())
           {
               //这里存 {订单编号 图书id 图书数量} 的 list即可
//               System.err.println("订单是否已经存入ES索引库？？"+searchService.insertBookList(bookList2));
               String test = addOrder(flBookOrder.getOrderId());
               log.warn("是否添加订单到RabbitMQ中?"+test);
               return Result.succ("创建订单成功",bookList);
           }
           return Result.fail("创建订单失败","");
       }


    @GetMapping("/serachOrderByOrderId/{orderId}")
    @ApiOperation(value="根据订单id查找订单信息",notes = "传入订单id")
     Result searchOrderByOrderId(@PathVariable("orderId") String orderId) throws IOException {
        System.out.println("传入的订单Id为"+orderId);

        FlBookOrder flBookOrder = flBookorderMapper.selectOrderByOrderId(orderId);
        if(flBookOrder!=null)
        {
            ArrayList arrayList=new ArrayList();
            //地址
            FlAddress flAddress=flAddressMapper.selectAddressByAddressId(flBookOrder.getAddressId());
            List<FlBookTemp> flBookTemp=flBookorderMapper.selectOrderTempByOrderId(orderId);
            arrayList.add(flAddress);
            arrayList.add(flBookOrder);
            for(int i=0;i<flBookTemp.size();i++)
            {
                Map linkedHashMap1=new LinkedHashMap();
                linkedHashMap1.put("bookDetail",flBookMapper.selectBookByISBN(flBookTemp.get(i).getBookId()));
                linkedHashMap1.put("bookCount",flBookTemp.get(i).getCount());
                arrayList.add(linkedHashMap1);
            }
            return Result.succ("查询订单成功",arrayList);
        }

//        List<Map<String,Object>> orderDetails = searchService.searchOrders(orderId);
//        if (orderDetails.size()!=0)
//        {
//            return Result.succ("查询订单信息成功",orderDetails);
//        }


        return Result.fail("查找失败","");
    }


    /**
     * 订单分页分状态思路 ：
     *
     * 首先应该是分状态查询 代付款订单 待发货订单 待收货订单 带评价订单 退款售后（这两个后续再加）
     * 其次是分页查询 之前一次显示太多订单 对用户不友好 等几秒钟才加载出来
     * 传入订单状态 type 用户id 当前页 每页显示条数
     */
    @PostMapping("/searchOrderByUserIdAndStatusType")
    @ApiOperation(value = "根据用户和订单状态查找订单信息",
            notes = "1 分状态图书订单查询 3 所有状态图书订单查询 2 分状态余额订单查询 4 所有状态余额订单查询"
                    +"!!!!!!查所有订单状态statusType顺便填！！")
    Result searchOrderByUserIdAndStatusType(@RequestBody SearchOrdersDTO searchOrdersDTO) throws IOException {
            String flag = "余额充值";
            Integer page = searchOrdersDTO.getPage();
            Integer pageSize = searchOrdersDTO.getPageSize();
            String userId = searchOrdersDTO.getUserId();
            //余额订单只有两种状态 未支付 已支付 （未支付订单会在24h内销毁掉）
            int status = searchOrdersDTO.getStatusType();
            FlBookOrder flBookOrder=new FlBookOrder();
            LinkedHashMap orderDetail = new LinkedHashMap<>();

            //未支付的余额订单
            Page<FlBookOrder> p =new Page<>(page,pageSize);
            Integer orderType = searchOrdersDTO.getOrderType();

            if(orderType==2)
            {
                IPage<FlBookOrder> flBookOrderPage = p.setRecords(flBookorderMapper.selectAccountOrderPageExt(p, flBookOrder, userId, status, flag));
                return Result.succ("查询余额订单成功！！",flBookOrderPage);
            }else if(orderType==4)
            {
                IPage<FlBookOrder> flBookOrderPage = p.setRecords(flBookorderMapper.selectAccountOrderPageExtAll(p, flBookOrder,userId, flag));
                return Result.succ("查询所有余额订单成功！！",flBookOrderPage);
            }else if(orderType==1)
            {
                p.setRecords(flBookorderMapper.selectBookOrderPageExt(p,flBookOrder,userId,status,flag));
                List<FlBookOrder> flBookOrders = p.getRecords();
                return  getBookOrder(flBookOrders,p);
            }
            else if(orderType==3)
            {
                IPage<FlBookOrder> flBookOrderIPage = p.setRecords(flBookorderMapper.selectAllBookOrderPageExt(p,flBookOrder,userId));

                List<FlBookOrder> flBookOrders =flBookOrderIPage.getRecords();

                return getBookOrder(flBookOrders,p);
            }

        return Result.fail("查询订单失败","");
    }



    @GetMapping("/searchOrderByUserId")
    @ApiOperation(value = "根据用户查找订单信息",notes = "传入用户id即可")
    Result searchOrderByUserId(@RequestParam("userId")String userId
                               ) throws IOException {
          Instant inst1 = Instant.now();
          List<FlBookOrder> flBookOrders = flBookorderMapper.selectOrderByUserId(userId);

//          System.err.println(flBookOrders.size());
          if(flBookOrders.size()!=0)
          {
              ArrayList linkedList =new ArrayList();

              for(int i=0;i<flBookOrders.size();i++)
              {
                  Instant instA = Instant.now();
                  List<FlBookTemp> bookTempList=flBookorderMapper.selectOrderTempByOrderId(flBookOrders.get(i).getOrderId());

                  System.out.println("bookTempList长度为："+bookTempList.size());
                  ArrayList arrayList1 = new ArrayList();
                  Map linkedHashMap2=new LinkedHashMap();


                   for(int j=0;j<bookTempList.size();j++)
                  {
                      System.out.println("你进来了吗？？？");
                      Map linkedHashMap1=new LinkedHashMap();
                      //应该是这里用时比较长 排除
//                      Instant inst4 = Instant.now();
                      System.out.println("map:"+"start");
                      Map<String, Object> map = searchService.searchBooks(1, bookTempList.get(j).getBookId(), 1, 1).get(1);
                      System.out.println("map:"+map);
                      //flBookMapper.selectBookByISBN(bookTempList.get(j).getBookId()).getImg()
                      linkedHashMap1.put("bookImg",map.get("img"));
                      linkedHashMap1.put("bookTitle",map.get("title"));
//                      Instant inst5 = Instant.now();
//                      System.err.println("查询所需时间为(单位毫秒)"+ Duration.between(inst4, inst5).toMillis());
                      System.out.println("临时"+linkedHashMap1);
                      arrayList1.add(linkedHashMap1);
                  }
                  linkedHashMap2.put("orderStatus",flBookOrders.get(i).getStatus());
                  linkedHashMap2.put("orderId",flBookOrders.get(i).getOrderId());
                  linkedHashMap2.put("createTime",flBookOrders.get(i).getCreateTime());
                  linkedHashMap2.put("paymentTime",flBookOrders.get(i).getPaymentTime());
                  linkedHashMap2.put("payment",flBookOrders.get(i).getPayment());

                  if(flAddressMapper.selectAddressByAddressId(
                          flBookOrders.get(i).getAddressId()
                  )!=null)
                  {
                      linkedHashMap2.put("receiveName",flAddressMapper.selectAddressByAddressId(
                              flBookOrders.get(i).getAddressId()
                      ).getReceiveName());
                  }

                  arrayList1.add(linkedHashMap2);
                  linkedList.add(arrayList1);
                  Instant instB = Instant.now();
                  System.err.println("A--B:"+Duration.between(instA,instB).toMillis());
              }

              Instant inst = Instant.now();
              System.err.println("查询所需总时间为(单位毫秒)"+ Duration.between(inst1, inst).toMillis());
              return Result.succ("查询成功！！",linkedList);
          }

        return Result.fail("查询所有订单信息失败","为空或者无订单");
    }


    public Result getBookOrder(List<FlBookOrder> flBookOrders, Page<FlBookOrder> p ) throws IOException {

        ArrayList allOrder =new ArrayList();
        LinkedHashMap orderDetail = new LinkedHashMap<>();

//        ArrayList orderIdList = new ArrayList<String>();
//        for (FlBookOrder flBookOrder : flBookOrders) {
//            orderIdList.add(flBookOrder.getOrderId());
//        }
//        List<FlBookTemp> flBookTemps = flBookorderMapper.selectOrderTempByOrderIdList(orderIdList);



        for(int i=0;i<flBookOrders.size();i++)
        {
            log.info("进入工具类GetAllBookOrderDetailUtils的订单遍历方法了");
            log.info(String.valueOf(flBookOrders.get(i)));
            Instant instA = Instant.now();
            List<FlBookTemp> bookTempList=flBookorderMapper.selectOrderTempByOrderId(flBookOrders.get(i).getOrderId());

            System.out.println("bookTempList长度为："+bookTempList.size());
//            System.out.println("flBookTemps长度为："+flBookTemps.size());

            //a1 是一个订单的小的组成部分有很多本书
            ArrayList a1 = new ArrayList();
            //a2 包括a1是一个订单的完全体
            ArrayList a2 = new ArrayList();
            Map l2=new LinkedHashMap();

            for(int j=0;j<bookTempList.size();j++)
            {
                Map l1=new LinkedHashMap();
                Map<String, Object> map = searchService.searchBooks(1, bookTempList.get(j).getBookId(), 1, 1).get(1);
                l1.put("bookImg",map.get("img"));
                l1.put("bookTitle",map.get("title"));
                System.out.println("临时"+l1);
                a1.add(l1);
            }
            l2.put("orderStatus",flBookOrders.get(i).getStatus());
            l2.put("orderId",flBookOrders.get(i).getOrderId());
            l2.put("createTime",flBookOrders.get(i).getCreateTime());
            l2.put("paymentTime",flBookOrders.get(i).getPaymentTime());
            l2.put("payment",flBookOrders.get(i).getPayment());

            if(flAddressMapper.selectAddressByAddressId(
                    flBookOrders.get(i).getAddressId()
            )!=null)
            {
                l2.put("receiveName",flAddressMapper.selectAddressByAddressId(
                        flBookOrders.get(i).getAddressId()
                ).getReceiveName());
            }

            a2.add(a1);
            a2.add(l2);
            allOrder.add(a2);
            Instant instB = Instant.now();
            System.err.println("A--B:"+ Duration.between(instA,instB).toMillis());
        }
        log.info((String) new HashMap<>().put("total",p.getTotal()));
        orderDetail.put("orderDetail",allOrder);
        orderDetail.put("total",p.getTotal());
        return Result.succ("查询订单成功！！",orderDetail);
    }
}
